use std::time::Duration;

use serde::{Deserialize, Serialize};

use crate::{config, Error, Result};

const VERIFY_URL: &str = "https://hcaptcha.com/siteverify";

#[derive(Serialize)]
pub struct Request<'a> {
    pub secret: &'a str,
    pub response: &'a str,
}
#[derive(Deserialize)]
pub struct Response {
    pub success: bool,
}

pub struct HCaptcha {
    secret: String,
    timeout: Duration,
}

impl HCaptcha {
    pub fn new(secret: &str, timeout: Duration) -> Self {
        Self {
            secret: secret.into(),
            timeout,
        }
    }

    pub fn from_cfg(cfg: &config::HCaptchaConfig) -> Self {
        let timeout = Duration::from_secs(cfg.request_timeout as u64);
        Self::new(&cfg.secret_key, timeout)
    }

    pub async fn verify(&self, response: &str) -> Result<bool> {
        let req = Request {
            secret: &self.secret,
            response,
        };

        let client = reqwest::ClientBuilder::new()
            .timeout(self.timeout)
            .build()
            .map_err(Error::from)?;

        let res = client
            .post(VERIFY_URL)
            .form(&req)
            .send()
            .await
            .map_err(Error::from)?;
        let res = res.text().await.map_err(Error::from)?;
        let res = serde_json::from_str::<Response>(res.as_str()).map_err(Error::from)?;

        Ok(res.success)
    }
}
